#ifndef ARCHIVE_ARCHIVELOADER
#define ARCHIVE_ARCHIVELOADER

#pragma warning(push)
#pragma warning(disable:4244)

#include <fstream>
#include <ios>
#include <map>

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>

#include "Archive/ILoader.hpp"
#include "Archive/File.hpp"
namespace Archive{
class ArchiveIStream
{
public:
	ArchiveIStream(const char* filename):
	 ifs(filename,std::ios::in | std::ios::binary)
	{
		fis.push(boost::iostreams::zlib_decompressor());
		fis.push(ifs);
	}
	bool fail()const
	{
		return ifs.fail();
	}
	bool eof()const
	{
		return fis.eof();
	}
	int readInt()
	{
		union{
			int value;
			char bin[sizeof(int)];
		}toValue;

		for(int i = 0 ; i < sizeof(int) ; ++i)
		{
			toValue.bin[i] = fis.get();
		}
		return toValue.value;
	}
	void readByte(char* pDest,int bytes)
	{
		fis.read(pDest,bytes);
	}
	std::string readString()
	{
		int length = this->readInt();
		if(this->eof()){return "";}

		std::vector<char> buf(length+1);
		this->readByte(&buf[0],length);
		buf[length]= '\0';
		return std::string(&buf[0]);
	}
private:
	std::ifstream ifs;
	boost::iostreams::filtering_istream fis;
};
class ArchiveLoader : public ILoader
{
public:
	ArchiveLoader(const char* filename):
	 ais(filename)
	{
		if(ais.fail())
		{
			//assert(0);
			throw std::ios_base::failure("ArchiveFile Not Found");
		}

		for(;;)
		{
			std::string filename = ais.readString();

			if(ais.eof())
			{
				break;
			}

			File* pFile = new Archive::File();
			pFile->m_filename = filename;
			
			int fileSize = ais.readInt();
			pFile->m_data.resize(fileSize);

			ais.readByte(reinterpret_cast<char*>(&pFile->m_data[0]),fileSize);

			fileList[filename] = IFile::ptr( pFile );
		}
	}
	virtual IFile::ptr load(const char* filename)
	{
		FileList::iterator it = fileList.find(filename);
		if(it != fileList.end())
		{
			return it->second;
		}
		return IFile::ptr();
	}
private:
	ArchiveIStream ais;

	typedef std::map<std::string,IFile::ptr> FileList;
	FileList fileList;
};
}//Archive

#pragma warning(pop)
#endif

